module ChartHelper

	def status_matches_filter(status)
		return (status.is_closed? or status.to_s == "Resolved")
	end

	def get_first_matching_update_date(issue)
		# Search in the history of the issue, if the status changed to close or resolved
        # FOLLOWING line is not compatible with redmine 1.4
		# journals = issue.journals.includes(:details).reorder("#{Journal.table_name}.id ASC").all
        journals = issue.journals.find(:all, :include => [:details], :order => "#{Journal.table_name}.created_on ASC")
		if journals.any?
			journals.each do |journal|
				if journal.details.any?
					journal.details.each do |detail|
			  			case detail.property
						when 'attr'
							field = detail.prop_key.to_s.gsub(/\_id$/, "")
							case detail.prop_key
							when 'status_id'
								status = IssueStatus.find(detail.value)
								if status_matches_filter(status)
									return journal.created_on.to_date
								end
							end
						end
					end
				end
			end
		end

		# Test if the issue matches the filter at creation
		if status_matches_filter(issue.status)
			return issue.created_on.to_date
		end

		# No date found
		return nil
	end	

	def filter_issue_by_first_matching_update_date(issues)
		filtered_issues_by_date = Hash.new

		issues.each do |issue|
			date = get_first_matching_update_date(issue)
			if !date.nil?
				filtered_issues_by_date[date] = Array.new unless filtered_issues_by_date[date]
				filtered_issues_by_date[date] << issue
			end
		end

		return filtered_issues_by_date.sort
	end

	def render_chart_data(title, issue_line)
		# construct the datas for the graph of the issue map
        # we try to minimize the number of plots in the graph, so we don't display plot if the value doesn't change
        data = ""
        data << "{name: '" << title << "',type: 'line',marker: {enabled: false},\n data: [\n"
        lastdate = -1
        lastVal = 0
        issue_line.sort.map do |key, value|
            # if the value change and the value is not fake
            if value != lastVal and value != -1
                if lastdate != -1
                    # display the last value at the last date
                    data << "[Date.parse('" << lastdate<< "')," << lastVal.to_s << "],\n"
                end
                # display the new value
                data << "[Date.parse('" << key<< "')," << value.to_s << "],\n"
                lastVal = value
            end
            # update the value of the map for the difference computation
            issue_line[key] = lastVal
            # store the last date
            lastdate = key
        end
        data << "[Date.parse('" << lastdate<< "')," << lastVal.to_s << "]\n"
        data << "]\n}\n"
        return data
	end

	def render_chart_series(issues)
		series = "series: [\n"

        # Display all the issues
        all_issues_by_date = issues.group_by {|issue| issue.created_on.to_date }.sort

        issue_count = 0
        all_issue_line = Hash.new
        all_issues_by_date.each { |created_on, grouped_issues| 
            issue_count += grouped_issues.size; all_issue_line[created_on.to_s] = issue_count 
        }
        all_issue_line[Date.today.to_s] = issue_count


        # Get the filtered issue
        filtered_issues_by_date = filter_issue_by_first_matching_update_date(issues)

        issue_count = 0
        filtered_issue_line = Hash.new
        filtered_issues_by_date.each { |updated_on, grouped_issues| 
            issue_count += grouped_issues.size; filtered_issue_line[updated_on.to_s] = issue_count 
        }
        filtered_issue_line[Date.today.to_s] = issue_count

        # create a clone of the all_issue map, with fake values (-1)
        all_issue_line_clone = all_issue_line.clone
        all_issue_line_clone.map do |key, value|
            all_issue_line_clone[key] = -1
        end

        # create a clone of the filtered_issue map, with fake values (-1)
        filtered_issue_line_clone = filtered_issue_line.clone
        filtered_issue_line_clone.map do |key, value|
            filtered_issue_line_clone[key] = -1
        end

        # merge the all_issue map with the clone filtered_issue map, in order to have a map with all the dates
        # if a date is in both maps, we keep the value of the all_issue map
        all_issue_line      = all_issue_line.merge(filtered_issue_line_clone) {|key, oldval, newval| oldval}
        # same thing with the filtered_issue map
        filtered_issue_line = filtered_issue_line.merge(all_issue_line_clone) {|key, oldval, newval| oldval}

        # construct the datas for the graph of the all_issue map
        series << render_chart_data("Total", all_issue_line) << ","

        # construct the graph content for the filtered_issue map
        series << render_chart_data("Closed & Resolved", filtered_issue_line) << ","
 
        # merge the all_issue map with the filtered_issue map in order to have a difference_issue map
        # the resulting map contains the difference between the all_issue values and the filtered_issue values
        diff_issue_line = all_issue_line.merge(filtered_issue_line) {|key, oldval, newval| oldval - newval}

        # construct the graph content for the difference_issue map
        series << render_chart_data("Difference", diff_issue_line) << "]"

        series.html_safe
	end
end
